package com.yuyou.fn.tms.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.wens.mybatisplus.examples.Example;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.BeanUtils;
import com.yuyou.fn.common.util.BigDecimals;
import com.yuyou.fn.common.util.Utils;
import com.yuyou.fn.educational.discount.DiscountRegClassInfo;
import com.yuyou.fn.educational.discount.DiscountRegCourseClass;
import com.yuyou.fn.educational.entity.CourseClass;
import com.yuyou.fn.educational.entity.CourseOrder;
import com.yuyou.fn.educational.entity.Student;
import com.yuyou.fn.educational.entity.StudentReg;
import com.yuyou.fn.educational.service.*;
import com.yuyou.fn.educational.vo.*;
import com.yuyou.fn.settlement.entity.NewPayRecord;
import com.yuyou.fn.settlement.service.IBalanceLockRecordService;
import com.yuyou.fn.settlement.service.INewPayRecordService;
import com.yuyou.fn.settlement.vo.PayWay;
import com.yuyou.fn.tms.service.IOrderService;
import com.yuyou.fn.tms.vo.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements IOrderService {

    private enum FopType{

        CASH(1),POS(1 << 1), TRANSFER( 1 << 2 ),ACCOUNT(1 << 3),CHECK(1 << 4),WX( 1<< 5 ),ALIPAY( 1 << 6 );

        int type;

        FopType(int type) {
            this.type = type;
        }
    }

    @Resource
    private IDegreeLockRecordService degreeLockRecordService ;

    @Resource
    private IBalanceLockRecordService balanceLockRecordService ;

    @Resource
    private IEmployeeDiscountService employeeDiscountService ;

    @Resource
    private IThirdpartyDiscountCodeService thirdpartyDiscountCodeService ;

    @Resource
    private ICourseClassService courseClassService ;

    @Resource
    private IStudentService studentService ;

    @Resource
    private IDiscountCalculateService discountCalculateService ;

    @Resource
    private ICourseOrderService courseOrderService ;

    @Resource
    private IStudentRegService studentRegService ;

    @Resource
    private INewPayRecordService newPayRecordService ;


    @Transactional
    @Override
    public void lockBalanceAndDegree(LockBalanceAndDegreeParam requestParam) {
        if(requestParam.getAccMoney() == null ){
            requestParam.setAccMoney(BigDecimal.ZERO);
        }
        List<Long> classIds = Utils.toLongIds(requestParam.getClassIDs());
        Collections.sort(classIds);
        String lockKey = createLockKey(classIds , requestParam.getStuId(),requestParam.getAccMoney() );
        degreeLockRecordService.lock( classIds , requestParam.getStuId(),lockKey );
        balanceLockRecordService.lock(requestParam.getStuId(),lockKey,requestParam.getAccMoney(),"集团网报锁定");

    }

    @Transactional
    @Override
    public void unlockBalanceAndDegree(UnlockBalanceAndDegreeParam requestParam) {
        if(requestParam.getAccMoney() == null ){
            requestParam.setAccMoney(BigDecimal.ZERO);
        }
        List<Long> classIds = Utils.toLongIds(requestParam.getClassIDs());
        Collections.sort(classIds);
        String lockKey = createLockKey(classIds , requestParam.getStuId(),requestParam.getAccMoney() );
        degreeLockRecordService.unlock(classIds,requestParam.getStuId(),lockKey);
        balanceLockRecordService.unlock(requestParam.getStuId(),lockKey , requestParam.getAccMoney() );
    }

    private String createLockKey(List<Long> classIds, Long studentId, BigDecimal amount) {
        return DigestUtils.md5Hex( StringUtils.join(classIds,",") + studentId + BigDecimals.formatBigDecimal(amount,"0.00")) + "tms" ;
    }

    @Override
    public TmsEmployeeCouponCode queryEmployeeCouponCode(QueryEmployeeCouponCodeParam requestParam) {
        EmployeeDiscountVo employeeDiscountVo = employeeDiscountService.query(requestParam.getCode(), requestParam.getStuName(), requestParam.getStuId().toString());
        TmsEmployeeCouponCode employeeCouponCode = new TmsEmployeeCouponCode();
        BeanUtils.copyProperties(employeeCouponCode,employeeDiscountVo);
        employeeCouponCode.setApplyClaIds(requestParam.getSubjectsClassIDList());
        return employeeCouponCode;
    }

    @Override
    public List<TmsECoupon> queryECoupon(QueryECouponParam requestParam) {
        List<ThirdpartyDiscountCodeVo> list = thirdpartyDiscountCodeService.queryList(requestParam.getPhone(),requestParam.getStuName(), requestParam.getStuId().toString() );
        return Lists.transform(list,item -> {
            TmsECoupon eCoupon = new TmsECoupon();
            BeanUtils.copyProperties(eCoupon,item);
            eCoupon.setCanUsed(0);
            eCoupon.setApplyClaIds(requestParam.getSubjectsClassIDList());
            return eCoupon ;
        });
    }

    @Override
    public TmsDiscountResult queryEcouponPre(QueryEcouponPreParam requestParam) {

        String[] classIds = requestParam.getSubjectsClassIDList().split(",");
        String[] starts = requestParam.getClaStartNums().split(",") ;
        String[] ends = requestParam.getClaEndNums().split(",") ;

        String[] payStarts = requestParam.getClaPayStartNums().split(",") ;
        String[] payEnds = requestParam.getClaPayEndNums().split(",") ;

        if(classIds.length != starts.length || classIds.length != ends.length ){
            throw new BusException("Illegal args");
        }


        Long studentId = requestParam.getStuId() ;
        List<CourseClass> courseClasses = courseClassService.findByIds(Lists.transform(Arrays.asList(classIds), i -> Long.valueOf(i)));

        Map<Long, CourseClass> classId2CourseClassMap = BeanUtils.toMap( courseClasses ,"classId");
        Student student = studentService.findById(studentId);


        List<DiscountRegClassInfo> discountRegClassInfoList  = new ArrayList<>(classIds.length);
        for(int i = 0 ; i < classIds.length ; i++ ){
            Long classId = Long.valueOf(classIds[i]);
            CourseClass courseClass =  classId2CourseClassMap.get(classId);
            DiscountRegClassInfo discountRegClassInfo = new DiscountRegClassInfo();
            BeanUtils.copyProperties(discountRegClassInfo,courseClass);
            discountRegClassInfo.setStartAmount(Integer.valueOf(starts[i]));
            discountRegClassInfo.setEndAmount(Integer.valueOf(ends[i]));
            discountRegClassInfo.setTotalAmount(calFee(courseClass.getStudyingFee(),(discountRegClassInfo.getEndAmount() - discountRegClassInfo.getStartAmount() + 1 ) , courseClass.getLectureAmount()));
            discountRegClassInfo.setFullReg( discountRegClassInfo.getEndAmount() - discountRegClassInfo.getStartAmount() + 1 == courseClass.getLectureAmount() );
            discountRegClassInfo.setRegDivSegment(1);
            discountRegClassInfoList.add(discountRegClassInfo);
        }



        List<TmsDiscountResult.Rd> rds = new ArrayList<>(classIds.length);
        for(int i = 0 ; i < classIds.length ; i++ ){
            Long classId = Long.valueOf(classIds[i]);
            CourseClass courseClass =  classId2CourseClassMap.get(classId);

            TmsDiscountResult.Regist regist = new TmsDiscountResult.Regist();
            regist.setRegClassId(courseClass.getClassId());//班级Id
            regist.setRegStudentId(studentId);//学生ID
            regist.setRegPayed(0);//是否已付款，理论上总是0
            regist.setRegBusinessType(0);//业务类型（0:小班，1：代收）
            regist.setRegStartNum(Integer.valueOf(starts[i]));//起始讲次
            regist.setRegEndNum(Integer.valueOf(ends[i]));//结束讲次
            regist.setPayStartNum(Integer.valueOf(payStarts[i]));//缴费起始讲次
            regist.setPayEndNum(Integer.valueOf(payEnds[i]));//缴费结束讲次
            regist.setRegPrice(calFee( courseClass.getStudyingFee(),(regist.getRegEndNum() - regist.getRegStartNum() + 1 ) , courseClass.getLectureAmount()));//报名原价（优惠前学费+资料费）
            regist.setRegPayPrice(regist.getRegPrice());//报名优惠后的价格（优惠后学费+资料费）
            regist.setRegMaterialFee(BigDecimal.ZERO);//资料费
            regist.setRegIsMaterial(1);//是否需要资料费（0为需要，1为不需要），网报总是需要
            regist.setClaYear(Integer.valueOf(courseClass.getPeriodName().substring(0,4)));//年份
            regist.setSeaId(courseClass.getPeriodId());//季节
            regist.setRegIsAll(courseClass.getLectureAmount() == ( regist.getRegEndNum() - regist.getRegStartNum() + 1  ));//是否完整报读
            regist.setCanUseVou(requestParam.getCoupons() == null || requestParam.getCoupons().isEmpty() ? false : true );//是否能使用优惠和优惠券
            regist.setRegClaFee(courseClass.getStudyingFee());//报名的学费（优惠前）

            if(regist.getRegStartNum() < 0 || regist.getRegEndNum() > courseClass.getLectureAmount() ){
                throw new BusException("报读讲次超出课程设置");
            }

            if( !regist.getRegStartNum().equals(regist.getPayStartNum())){
                throw new BusException("起始讲次不等于缴费起始讲次");
            }

            if(regist.getRegEndNum() < regist.getPayEndNum()){
                throw new BusException("缴费结束讲次大于结束讲次");
            }

            TmsDiscountResult.Rd rd = new TmsDiscountResult.Rd();
            rd.setRegist(regist);
            rd.setRegClaId(classId);//报名班级ID
            rd.setPraDetail(null);//该报名的优惠详情描述
            rd.setPraAllMoney(BigDecimal.ZERO);//该报名总共优惠了多少钱
            rd.setCurrMoney(BigDecimal.ZERO);//报名优惠后的学费（不包含资料费）
            rd.setPayCurrMoney(BigDecimal.ZERO);//当前缴费讲次的优惠后学费（不包含资料费）
            rd.setPayPraAllMoney(BigDecimal.ZERO);//当前缴费讲次的优惠金额
            rd.setPayCurrPrice(BigDecimal.ZERO);//当前缴费讲次的原价学费（不包含资料费）
            rd.setRegistDiscounts(new ArrayList<>());//优惠的详情，每个优惠对应一个


            rds.add(rd);
        }


        if( !containsSpecialCoupon(requestParam.getCoupons(),0 )){//0 是内部员工优惠
            List<DiscountInfoVo> discountInfoVos = discountCalculateService.calOnlineDiscount(courseClasses.get(0).getAreaTeamId(), Arrays.asList(new DiscountRegCourseClass(student, discountRegClassInfoList))).get(studentId);
            shareDiscountToEachCourseClass(rds,discountInfoVos);
        }else{
            requestParam.setCoupons(requestParam.getCoupons().stream().filter(c -> c.getType() == 0 ).collect(Collectors.toList()));
        }
        shareCouponsEachCourseClass(rds,requestParam.getCoupons());



        for(TmsDiscountResult.Rd rd : rds ){

            //rd.setPraAllMoney(BigDecimals.min(rd.getRegist().getRegPrice(),rd.getPraAllMoney()));
            rd.getRegist().setRegPayPrice(rd.getRegist().getRegPrice().subtract(rd.getPraAllMoney() ));
            rd.setCurrMoney(rd.getRegist().getRegPayPrice());

            //计算当前讲次缴费
            if(rd.getRegist().getRegEndNum().equals(rd.getRegist().getPayEndNum())){
                rd.setPayPraAllMoney(rd.getPraAllMoney()) ;
                rd.setPayCurrMoney(rd.getRegist().getRegPayPrice()) ;
            }else{
                int regAmount = rd.getRegist().getRegEndNum() - rd.getRegist().getRegStartNum() + 1 ;
                int payAmount  = rd.getRegist().getPayEndNum() - rd.getRegist().getPayStartNum() + 1 ;
                BigDecimal p1 = BigDecimals.integer(BigDecimals.calProportion(rd.getRegist().getRegPrice(),BigDecimal.valueOf(payAmount), BigDecimal.valueOf(regAmount )) );
                BigDecimal p2 = BigDecimals.integer(BigDecimals.calProportion(rd.getRegist().getRegPayPrice(),BigDecimal.valueOf(payAmount), BigDecimal.valueOf(regAmount )) );
                rd.setPayCurrMoney(p2) ;
                rd.setPayPraAllMoney(p1.subtract(p2)) ;
            }
            rd.setPayCurrPrice(rd.getPayCurrMoney().add(rd.getPayPraAllMoney())) ;
        }

        TmsDiscountResult tmsDiscountResult = new TmsDiscountResult() ;

        //set phone
        if(requestParam.getCoupons() != null ){
            for(TmsCoupon coupon : requestParam.getCoupons() ){
                coupon.setPhone(student.getPhoneNo());
            }
        }

        tmsDiscountResult.setUsedCoupons(requestParam.getCoupons());
        tmsDiscountResult.setOriginPrice(BigDecimal.ZERO);//订单原价（每个报名的学费+资料费）
        tmsDiscountResult.setCurrPrice(BigDecimal.ZERO);//优惠后订单价格（每个报名优惠后学费+资料费）
        tmsDiscountResult.setPayOriginPrice(BigDecimal.ZERO);//当前缴费讲次的订单原价（每个报名缴费讲次的学费+资料费）
        tmsDiscountResult.setPayCurrPrice(BigDecimal.ZERO);//当前缴费讲次的订单应缴（优惠后价格）（每个报名缴费讲次的优惠后学费+资料费）


        for(TmsDiscountResult.Rd rd : rds ){
            tmsDiscountResult.setOriginPrice(tmsDiscountResult.getOriginPrice().add(rd.getRegist().getRegPrice()));
            tmsDiscountResult.setCurrPrice(tmsDiscountResult.getCurrPrice().add(rd.getRegist().getRegPrice().subtract(rd.getPraAllMoney())));
            tmsDiscountResult.setPayOriginPrice(tmsDiscountResult.getPayOriginPrice().add(rd.getPayCurrPrice()));
            tmsDiscountResult.setPayCurrPrice(tmsDiscountResult.getPayCurrPrice().add( rd.getPayCurrPrice().subtract(rd.getPayPraAllMoney())));
        }
        tmsDiscountResult.setRdList(rds);

        return tmsDiscountResult;
    }

    private boolean containsSpecialCoupon(List<TmsCoupon> coupons, int type) {
        if(coupons == null || coupons.isEmpty() ){
            return false ;
        }
        return coupons.stream().anyMatch((c) -> c.getType() == type );
    }

    private void shareCouponsEachCourseClass(List<TmsDiscountResult.Rd> rds, List<TmsCoupon> coupons) {

        if(coupons == null || coupons.isEmpty() ){
            return;
        }

        for(TmsCoupon coupon : coupons ){
            // -1无法处理 0折扣 1金额
            int stdDiscountType = -1 ;

            //0 是内部员工优惠，1是电子优惠券促销券,2是奖学金券
            if(coupon.getType() == 0 ){
                //优惠类型：0.折扣 1.课时 3.金额
                switch (coupon.getDiscountType()){
                    case 0 : stdDiscountType = 0;break;
                    case 1 : stdDiscountType = -1;break;
                    case 3 : stdDiscountType = 1;break;
                }
            }else if(coupon.getType() == 1 ){
                //折扣类型，0：立减、 1：满减、 2：折扣、 3：满折
                switch (coupon.getDiscountType()){
                    case 0 : stdDiscountType = 1;break;
                    case 1 : stdDiscountType = 1;break;
                    case 2 : stdDiscountType = -1;break;
                    case 3 : stdDiscountType = -1;break;
                }
            }

            //不处理
            if(stdDiscountType == -1 ){
                continue;
            }


            BigDecimal realDiscountAmount = BigDecimal.ZERO ;

            if(stdDiscountType == 0 ){

                BigDecimal total = BigDecimal.ZERO ;
                for(TmsDiscountResult.Rd rd : rds ){
                    total = total.add(rd.getRegist().getRegPrice().subtract(rd.getPraAllMoney()));
                }
                realDiscountAmount = total.subtract(BigDecimals.integer(total.multiply(coupon.getDiscountValue().divide(BigDecimal.valueOf(10)))));
            }else if(stdDiscountType == 1 ){
                realDiscountAmount = coupon.getDiscountValue() ;
            }


            BigDecimal orderPayableAmount = BigDecimal.ZERO;
            BigDecimal temp = BigDecimal.ZERO;

            for(TmsDiscountResult.Rd rd : rds ){
                orderPayableAmount = orderPayableAmount.add(rd.getRegist().getRegPrice().subtract(rd.getPraAllMoney()));
            }


            for(int i = 0 ; i < rds.size()  ; i++ ){
                TmsDiscountResult.Rd rd = rds.get(i);
                // 计算优惠分摊比例
                BigDecimal p  = BigDecimals.toFixed2( BigDecimals.calProportion(realDiscountAmount ,rd.getRegist().getRegPrice().subtract(rd.getPraAllMoney()) , orderPayableAmount ) , 2 ) ;

                if( i == rds.size() - 1 ){
                    p = realDiscountAmount.subtract(temp);
                }else {
                    temp = temp.add(p);
                }

                addDiscount(rd, coupon.getDiscountType() == 0 ? 2 : (coupon.getDiscountType() == 1 ? 3 : Long.valueOf(coupon.getDiscountType())) ,coupon.getMainCategoryName() , p , coupon.getCouponCode() );
            }
        }


    }


    private BigDecimal calFee(BigDecimal fee ,int regLecture , int  totalLecture){
        return BigDecimals.integer( BigDecimals.calProportion(fee,BigDecimal.valueOf(regLecture),BigDecimal.valueOf(totalLecture) )) ;
    }

  public void shareDiscountToEachCourseClass(  List<TmsDiscountResult.Rd> rds, List<DiscountInfoVo> discountInfoList) {
        Map<Long,TmsDiscountResult.Rd > classId2Rd = BeanUtils.toMap(rds,"regClaId");

        //合并最终优惠
        if(discountInfoList != null ){

            //处理扣减
            for(DiscountInfoVo discountInfoVo : Collections2.filter(discountInfoList, input -> input.getDiscountType() == 1 )){
                BigDecimal d  = BigDecimals.integer(BigDecimals.calProportion(discountInfoVo.getTotalDiscount(),BigDecimal.ONE,BigDecimal.valueOf(discountInfoVo.getClassIds().size()))) ;//分摊优惠
                BigDecimal sum = BigDecimal.ZERO;
                for(int i = 0 ; i < discountInfoVo.getClassIds().size();i++ ){
                    TmsDiscountResult.Rd rd = classId2Rd.get(discountInfoVo.getClassIds().get(i));
                    BigDecimal d2 = i == discountInfoVo.getClassIds().size() -1  ? discountInfoVo.getTotalDiscount().subtract(sum) : d;
                    sum = sum.add(d2);
                    //转换成每科减
                    addDiscount(rd,discountInfoVo.getDiscountId(), discountInfoVo.getDiscountName() , d2 , null);
                }
            }

            //处理折扣（折上折）
            for(DiscountInfoVo discountInfoVo : Collections2.filter(discountInfoList,input -> input.getDiscountType() == 0 )){
                BigDecimal discountRate = discountInfoVo.getTotalDiscount().divide(BigDecimal.valueOf(100));
                if(BigDecimals.compare(BigDecimal.ONE,discountRate ) < 0 ){
                    throw new BusException("折扣率大于1");
                }

                for(int i = 0 ; i < discountInfoVo.getClassIds().size();i++ ){
                    TmsDiscountResult.Rd rd = classId2Rd.get(discountInfoVo.getClassIds().get(i));
                    BigDecimal initAmount  = rd.getRegist().getRegPrice().subtract(rd.getPraAllMoney());
                    BigDecimal amount  = initAmount.multiply(discountRate);
                    BigDecimal discountAmount = BigDecimals.integer(initAmount.subtract(amount));
                    addDiscount(rd,discountInfoVo.getDiscountId(),discountInfoVo.getDiscountName(), discountAmount , null );

                }
            }

        }
    }

    @Transactional
    @Override
    public TmsSaveOrderResult saveOrder(SaveOrderParam requestParam) {

        List<Long> classIds = BeanUtils.toList(requestParam.getRegs(),"claId");

        UnlockBalanceAndDegreeParam unlockBalanceAndDegreeParam = new UnlockBalanceAndDegreeParam();
        unlockBalanceAndDegreeParam.setAccMoney(getAccMoney(requestParam));
        unlockBalanceAndDegreeParam.setClassIDs(StringUtils.join(classIds,","));
        unlockBalanceAndDegreeParam.setStuId(requestParam.getStuId());
        unlockBalanceAndDegree(unlockBalanceAndDegreeParam);

        Student student = studentService.findById(requestParam.getStuId());
        List<CourseClass> courseClasses = courseClassService.findByIds(classIds);

        CreateCourseOrderInfo createCourseOrderInfo = new CreateCourseOrderInfo();
        createCourseOrderInfo.setStudent(student);
        createCourseOrderInfo.setCourseClassList(courseClasses);
        createCourseOrderInfo.setDiscountInfoList(resolveDiscountInfoList(requestParam));
        createCourseOrderInfo.setRegClassInfoList(resolveRegClassInfoList(requestParam));
        createCourseOrderInfo.setFrom(3);
        createCourseOrderInfo.setNeedCheck(false);
        createCourseOrderInfo.setInt(false);
        CourseOrder courseOrder = courseOrderService.createOrder(createCourseOrderInfo, null);
        courseOrderService.payCourseOrder(courseOrder,resolvePayInfoOfCourseOrder(courseOrder.getCourseOrderId(),requestParam));

        return createTmsSaveOrderService(courseOrder.getCourseOrderId());
    }



    @Transactional
    @Override
    public TmsSaveOrderResult savePayOrder(SavePayOrderParam requestParam) {
        UnlockBalanceAndDegreeParam unlockBalanceAndDegreeParam = new UnlockBalanceAndDegreeParam();
        unlockBalanceAndDegreeParam.setAccMoney(getAccMoney(requestParam));
        unlockBalanceAndDegreeParam.setStuId(requestParam.getStuId());
        unlockBalanceAndDegree(unlockBalanceAndDegreeParam);
        CourseOrder courseOrder = courseOrderService.findById(requestParam.getOrder().getFinOrderId());
        courseOrderService.payCourseOrder(courseOrder,resolvePayInfoOfCourseOrder(courseOrder.getCourseOrderId(),requestParam));
        return createTmsSaveOrderService(courseOrder.getCourseOrderId());
    }

    private TmsSaveOrderResult createTmsSaveOrderService(Long courseOrderId) {
        CourseOrder courseOrder = courseOrderService.findById(courseOrderId);
        List<StudentReg> studentRegs = studentRegService.findStudentRegByCourseOrderId(courseOrderId);
        List<NewPayRecord> payRecords = newPayRecordService.findByBusOrderId(courseOrderId);
        TmsSaveOrderResult saveOrderResult = new TmsSaveOrderResult();
        saveOrderResult.setRegOrder(new TmsRegOrder(courseOrder));
        saveOrderResult.setRegList(Lists.transform(studentRegs,studentReg -> new TmsReg( studentReg,null, payRecords )));
        return saveOrderResult;
    }



    private PayInfoOfCourseOrder resolvePayInfoOfCourseOrder(Long courseOrderId , RequestParam requestParam) {
        Example<StudentReg> studentRegExample = StudentReg.createExample();
        studentRegExample.selectProperties("regId","classId");
        studentRegExample.createCriteria().andEqualTo("courseOrderId",courseOrderId );
        List<StudentReg> studentRegs = studentRegService.findListByExample(studentRegExample);
        Map<Long,StudentReg> classId2StudentReg = BeanUtils.toMap(studentRegs,"classId");
        PayInfoOfCourseOrder payInfoOfCourseOrder = new PayInfoOfCourseOrder();
        if(requestParam instanceof SaveOrderParam){
            SaveOrderParam saveOrderParam = (SaveOrderParam)requestParam ;
            List<PayLecture> payLectures = new ArrayList<>(saveOrderParam.getRegs().size());
            for(SaveOrderParam.Reg reg : saveOrderParam.getRegs()){
                PayLecture payLecture = new PayLecture() ;
                payLecture.setStart(reg.getClaPayStartNum());
                payLecture.setEnd(reg.getClaPayEndNum());
                payLecture.setPayAmount(reg.getRegPayPrice());
                payLecture.setRegId(classId2StudentReg.get(reg.getClaId()).getRegId());
                payLectures.add(payLecture);
            }
            List<PayWay> payWays = new ArrayList<>(saveOrderParam.getPayInfos().size());
            for(SaveOrderParam.PayInfo payInfo : saveOrderParam.getPayInfos() ){
                int payWay ;
                //支付方式：0-现金；1-刷卡；2-转账；3-账户 4-在线支付
                if (payInfo.getFopType() == FopType.CASH.type ){
                    payWay = 0 ;
                }else if(payInfo.getFopType() == FopType.POS.type){
                    payWay = 1 ;
                }else if(payInfo.getFopType() == FopType.TRANSFER.type){
                    payWay = 2 ;
                }else  if(payInfo.getFopType() == FopType.ACCOUNT.type){
                    payWay = 3 ;
                }else if(payInfo.getFopType() == FopType.WX.type || payInfo.getFopType() == FopType.ALIPAY.type ){
                    payWay = 4 ;
                }else {
                    throw new BusException("Unknown fopType=" + payInfo.getFopType() );
                }

                String morePayInfo = null ;

                if(payInfo.getFopType() == FopType.WX.type || payInfo.getFopType() == FopType.ALIPAY.type){
                    JSONObject payInfoExt = new JSONObject();
                    payInfoExt.put("transactionNo" ,payInfo.getFinaPayNo());
                    payInfoExt.put("channel" ,payInfo.getFopType() == FopType.WX.type ? "wx_pub" : "alipay_wap");
                    morePayInfo = payInfoExt.toJSONString();
                }
                payWays.add(new PayWay(payWay,payInfo.getFopPay(), morePayInfo ));
            }

            payInfoOfCourseOrder.setPayLectures(payLectures);
            payInfoOfCourseOrder.setPayAmount(sum(payWays));
            payInfoOfCourseOrder.setPayWays(payWays);
        }else if(requestParam instanceof SavePayOrderParam){
            SavePayOrderParam savePayOrderParam = (SavePayOrderParam)requestParam ;
            List<PayLecture> payLectures = new ArrayList<>(savePayOrderParam.getRegs().size());
            for(SavePayOrderParam.Reg reg : savePayOrderParam.getRegs()){
                PayLecture payLecture = new PayLecture() ;
                payLecture.setStart(reg.getClaPayStartNum());
                payLecture.setEnd(reg.getClaPayEndNum());
                payLecture.setPayAmount(reg.getRegPayPrice());
                payLecture.setRegId(classId2StudentReg.get(reg.getClaId()).getRegId());
                payLectures.add(payLecture);
            }
            List<PayWay> payWays = new ArrayList<>(savePayOrderParam.getPayInfos().size());
            for(SavePayOrderParam.PayInfo payInfo : savePayOrderParam.getPayInfos() ){
                int payWay ;
                //支付方式：0-现金；1-刷卡；2-转账；3-账户 4-在线支付
                if (payInfo.getFopType() == FopType.CASH.type ){
                    payWay = 0 ;
                }else if(payInfo.getFopType() == FopType.POS.type){
                    payWay = 1 ;
                }else if(payInfo.getFopType() == FopType.TRANSFER.type){
                    payWay = 2 ;
                }else  if(payInfo.getFopType() == FopType.ACCOUNT.type){
                    payWay = 3 ;
                }else if(payInfo.getFopType() == FopType.WX.type || payInfo.getFopType() == FopType.ALIPAY.type ){
                    payWay = 4 ;
                }else {
                    throw new BusException("Unknown fopType=" + payInfo.getFopType() );
                }

                String morePayInfo = null ;

                if(payInfo.getFopType() == FopType.WX.type || payInfo.getFopType() == FopType.ALIPAY.type){
                    JSONObject payInfoExt = new JSONObject();
                    payInfoExt.put("transactionNo" ,payInfo.getFinaPayNo());
                    payInfoExt.put("channel" ,payInfo.getFopType() == FopType.WX.type ? "wx_pub" : "alipay_wap");
                    morePayInfo = payInfoExt.toJSONString();
                }
                payWays.add(new PayWay(payWay,payInfo.getFopPay(), morePayInfo ));
            }

            payInfoOfCourseOrder.setPayLectures(payLectures);
            payInfoOfCourseOrder.setPayAmount(sum(payWays));
            payInfoOfCourseOrder.setPayWays(payWays);
        }

        return payInfoOfCourseOrder;
    }

    private BigDecimal sum(List<PayWay> payWays) {
        BigDecimal sum = BigDecimal.ZERO ;
        for(PayWay payWay : payWays ){
            sum = sum.add(payWay.getAmount());
        }
        return sum;
    }

    private List<RegClassInfoVo> resolveRegClassInfoList(SaveOrderParam requestParam) {
        List<RegClassInfoVo> list = new ArrayList<>(requestParam.getRegs().size());
        for(SaveOrderParam.Reg reg : requestParam.getRegs() ){
            RegClassInfoVo regClassInfoVo = new RegClassInfoVo();
            regClassInfoVo.setTotalAmount(reg.getRegPrice());
            regClassInfoVo.setClassId(reg.getClaId());
            regClassInfoVo.setStartAmount(reg.getClaStartNum());
            regClassInfoVo.setEndAmount(reg.getClaEndNum());
            regClassInfoVo.setCounselorId(requestParam.getOrder().getFinOrderAdvisorId());
            list.add(regClassInfoVo);
        }
        return list;
    }

    private List<DiscountInfoVo> resolveDiscountInfoList(SaveOrderParam requestParam) {

        List<DiscountInfoVo> list = new ArrayList<>(requestParam.getDiscounts().size());

        for(SaveOrderParam.Discount discount : requestParam.getDiscounts() ){

            DiscountInfoVo discountInfoVo = new DiscountInfoVo() ;
            discountInfoVo.setTotalDiscount(discount.getrDisMoney());
            discountInfoVo.setClassIds(Arrays.asList(discount.getClaId()));
            discountInfoVo.setDiscountId(discount.getrDisDisId());
            discountInfoVo.setDiscount(discount.getrDisVal());
            discountInfoVo.setDiscountName(discount.getrDisName());
            discountInfoVo.setTotalDiscount(discount.getrDisMoney());
            //全部转换成金额优惠
            discountInfoVo.setDiscountType(1);
            list.add(discountInfoVo);
        }
        return list ;

    }

    private BigDecimal getAccMoney(RequestParam requestParam) {
        if(requestParam instanceof SaveOrderParam){
            for(SaveOrderParam.PayInfo payInfo : ((SaveOrderParam)requestParam).getPayInfos()){
                if(payInfo.getFopType() == FopType.ACCOUNT.type ){
                    return payInfo.getFopPay();
                }
            }
        }else if(requestParam instanceof SavePayOrderParam){
            for(SavePayOrderParam.PayInfo payInfo : ((SavePayOrderParam)requestParam).getPayInfos()){
                if(payInfo.getFopType() == FopType.ACCOUNT.type ){
                    return payInfo.getFopPay();
                }
            }
        }
        return null ;
    }

    private void addDiscount(TmsDiscountResult.Rd rd ,Long discountId , String discountName, BigDecimal discountAmount , String couponCode ) {

        if(BigDecimals.compare( rd.getPraAllMoney().add(discountAmount) , rd.getRegist().getRegPrice() ) > 0 ){
            discountAmount = rd.getRegist().getRegPrice().subtract(rd.getPraAllMoney()) ;
        }

        if(BigDecimals.compare(discountAmount,BigDecimal.ZERO)==0){
            return ;
        }

        //转换成每科减
        TmsDiscountResult.Discount discount = new TmsDiscountResult.Discount();
        discount.setClaId(rd.getRegClaId());
        discount.setrDisDisId(discountId);
        discount.setrDisDisType(1);
        discount.setrDisMoney(discountAmount);
        discount.setrDisName(discountName);
        discount.setrDisStyle(1);
        discount.setrDisVal(discountAmount);
        discount.setCouponCode(couponCode);
        rd.getRegistDiscounts().add(discount);
        rd.setPraAllMoney(rd.getPraAllMoney().add(discountAmount));
    }



}
